#include <stdlib.h>

#include "constantes_et_macros.h"

#include "tests_regression.h"
#include "jeu.h"
#include "carte_zone.h"
#include "base_donnees.h"
#include "parsing.h"
#include "manipulation_cases.h"
#include "manipulation_ennemis.h"
#include "etat_bataille.h"
#include "resume_saisie.h"
#include "SDL/SDL.h"
#include "debut_et_fin.h"


void tester_carte_zone(const struct base_donnees* donnees)
{
    int i, j;
    struct carte_zone carte;
    struct etat_bataille bataille;
    struct case_constante* p_case;
    struct case_destructible* p_destr;
    struct ennemi* p_ennemi;
    struct etat_partie* partie;

    printf("===== tester_carte_zone =====\n");
    partie = creer_partie();
    charger_partie(partie, "Nom Test", VRAI);
    printf("Chargement de la zone 999 dans la region 999\n");
    charger_carte_zone(&carte, &bataille, 999, 999, donnees, partie);
    printf("Chargement termine\n\n");
    printf("Dimensions : %u x %u\n\n", carte.dim_x, carte.dim_y);
    printf("\n\nCases Constantes :\n\n");
    printf("id Tuiles :\n\n");
    for(j = 0;  j < carte.dim_y;  j++)
    {
        for(i = 0;  i < carte.dim_x;  i++)
        {
            p_case = get_case_constante_grille(&carte, i, j);
            printf("%u", p_case->id_tuile);
        }
        printf("\n");
    }
    printf("\n");
    printf("Relief :\n\n");
    for(j = 0;  j < carte.dim_y;  j++)
    {
        for(i = 0;  i < carte.dim_x;  i++)
        {
            p_case = get_case_constante_grille(&carte, i, j);
            printf("%u", p_case->relief);
        }
        printf("\n");
    }
    printf("\n");
    printf("Cases Destructibles :\n\n");
    printf("id Tuiles :\n\n");
    for(j = 0;  j < carte.dim_y;  j++)
    {
        for(i = 0;  i < carte.dim_x;  i++)
        {
            p_destr = get_case_destructible(&carte, i, j);
            if(p_destr)
                printf("%u", p_destr->id_tuile);
            else
                printf("x");
        }
        printf("\n");
    }
    printf("\n");
    printf("Groupes :\n\n");
    for(j = 0;  j < carte.dim_y;  j++)
    {
        for(i = 0;  i < carte.dim_x;  i++)
        {
            p_destr = get_case_destructible(&carte, i, j);
            if(p_destr)
                printf("%u", p_destr->groupe);
            else
                printf("x");
        }
        printf("\n");
    }
    printf("\n");
    printf("Pts de vie :\n\n");
    for(j = 0;  j < carte.dim_y;  j++)
    {
        for(i = 0;  i < carte.dim_x;  i++)
        {
            p_destr = get_case_destructible(&carte, i, j);
            if(p_destr)
                printf("%u", p_destr->pv_case);
            else
                printf("x");
        }
        printf("\n");
    }
    printf("\n");
    printf("Position de depart du joueur : (%u ; %u)\n", bataille.coord_j_x, bataille.coord_j_y);
    printf("Valeurs correctes : (4 ; 3)\n\n");
    printf("Verification des ennemis...\n");
    p_ennemi = bataille.ennemis.prem;
    while(p_ennemi)
    {
        printf("id : %u\n", p_ennemi->id);
        printf("Nom : %s\n", get_nom_ennemi(donnees, p_ennemi));
        printf("x : %u\n", p_ennemi->coord_x);
        printf("y : %u\n", p_ennemi->coord_y);
        printf("Vitesse deplacement : %u\n", get_vit_depl(donnees, p_ennemi));
        printf("Puissance : %u\n", get_puissance(donnees, p_ennemi));
        printf("Vitesse charge : %u\n", get_vit_charge(donnees, p_ennemi));
        printf("id projectile : %hu\n", get_id_projectile(donnees, p_ennemi));
        printf("Taille : %hu\n", get_taille(donnees, p_ennemi));
        printf("Localisation sprites : %u\n", get_loc_sprites(donnees, p_ennemi));
        printf("Pv : %u/%u\n", p_ennemi->pv, get_pv_max(donnees, p_ennemi));
        printf("Orientation : %d\n", p_ennemi->orientation);
        printf("Type attaque : ");
        switch(get_type_attaque(donnees, p_ennemi))
        {
            case CONTACT:
                printf("contact\n");
                break;
            case DISTANCE:
                printf("distance\n");
                break;
            default:
                printf("erreur : type non reconnu\n");
        }
        switch(get_stats_vol(donnees, p_ennemi))
        {
            case VRAI:
                printf("Volant\n");
                break;
            case FAUX:
                printf("Non-volant\n");
                break;
            default:
                printf("erreur : donnees de vol non reconnues\n");
        }
        printf("Score de deplacement : %u\n", p_ennemi->score_deplacement);
        printf("Score de charge : %u\n", p_ennemi->score_charge);
        printf("\n\n");
        p_ennemi = p_ennemi->suiv;
    }

    detruire_etat_bataille(&bataille);
    detruire_carte_zone(&carte);
    detruire_partie(partie);
    printf("===== fin tester_carte_zone =====\n");
}





void tester_base_donnees(const struct base_donnees* donnees)
{
    int i, j;

    /*
     * cette fonction cree et remplie une struct base_donnees, puis affiche
     * le contenu de cette base_donnees. Si tout se passe bien, ce contenu doit
     * etre conforme aux donnees visibles dans les fichiers textes concernes
     */
    printf("===== tester_base_donnees =====\n");
    /* ===== ennemis ===== */
    printf("%u ennemis dans la base de donnees\n\n", donnees->tab_ennemis.nb_elements);
    for(i = 0;  i < donnees->tab_ennemis.nb_elements;  i++)
    {
        /*
         * ici, on ne peut pas utiliser les accesseurs, car ils sont prevus
         * pour etre utilises avec des struct ennemi* et non
         * avec des id ou des struct description_ennemi*
         */
        printf("# %d\n", i);
        printf("%s\n", donnees->tab_ennemis.tab[i].nom);
        printf("%u\n%u %u %u\n%hu %hu %u\n",
               donnees->tab_ennemis.tab[i].pv,
               donnees->tab_ennemis.tab[i].vitesse_deplacement,
               donnees->tab_ennemis.tab[i].puissance,
               donnees->tab_ennemis.tab[i].vitesse_charge,
               donnees->tab_ennemis.tab[i].id_projectile,
               donnees->tab_ennemis.tab[i].taille,
               donnees->tab_ennemis.tab[i].localisation_sprites);
        switch(donnees->tab_ennemis.tab[i].type_attaque)
        {
            case CONTACT:
                printf("c");
                break;
            case DISTANCE:
                printf("d");
                break;
            default:
                printf("Erreur : type d'attaque non reconnu\n");
                exit(EXIT_FAILURE);
        }
        switch(donnees->tab_ennemis.tab[i].volant)
        {
            case VRAI:
                printf(" 1\n");
                break;
            case FAUX:
                printf(" 0\n");
                break;
            default:
                printf("Erreur : donnee de vol non reconnue\n");
                exit(EXIT_FAILURE);
        }
        printf("%hu\n", donnees->tab_ennemis.tab[i].drops.nb_elements);
        for(j = 0;  j < donnees->tab_ennemis.tab[i].drops.nb_elements;  j++)
        {
            printf("%u %u\n", donnees->tab_ennemis.tab[i].drops.tab[j],
                              donnees->tab_ennemis.tab[i].probas.tab[j]);
        }
        printf("\n\n");
    }
    printf("Veuillez verifier que la sortie du programme correspond au\n");
    printf("contenu du fichier ennemis.txt\n\n\n");
    /* ===== objets ===== */
    printf("%u objets dans la base de donnees\n\n", donnees->tab_objets.nb_elements);
    for(i = 0;  i < donnees->tab_objets.nb_elements;  i++)
    {
        printf("# %d\n", i);
        printf("%s\n", get_nom_objet(donnees, i));
        printf("%c %u %u %u %u %u %u\n\n\n", get_type_objet(donnees, i),
               get_pv_objet(donnees, i), get_vitesse_deplacement_objet(donnees, i),
               get_puissance_objet(donnees, i), get_vitesse_charge_objet(donnees, i),
               get_id_projectile_objet(donnees, i), get_prix_vente(donnees, i));
    }
    printf("Veuillez verifier que la sortie du programme correspond au\n");
    printf("contenu du fichier objets.txt\n\n\n");
    /* ===== projectiles ===== */
    printf("%u projectiles dans la base de donnees\n\n", donnees->tab_projectiles.nb_elements);
    for(i = 0;  i < donnees->tab_projectiles.nb_elements;  i++)
    {
        printf("# %d\n", i);
        printf("%u %u %u\n\n\n",
               donnees->tab_projectiles.tab[i].localisation_sprites,
               donnees->tab_projectiles.tab[i].vitesse_deplacement,
               donnees->tab_projectiles.tab[i].taille);
    }
    printf("Veuillez verifier que la sortie du programme correspond au\n");
    printf("contenu du fichier objets.txt\n\n\n");
    /* ===== niveaux ===== */
    printf("Verification des paliers d'experience :\n");
    for(i = 0;  i < 98;  i++)
    {
        printf("%d - %u", i + 1, donnees->paliers_xp[i]);
        if(i % 5 == 4)
            printf("\n");
        else
            printf("   ");
    }
    printf("\n");
    printf("Veuillez verifier que la sortie du programme correspond au\n");
    printf("contenu du fichier niveaux.txt\n\n\n");
    printf("===== fin tester_base_donnees =====\n");
}



void tester_ennemis(const struct base_donnees* donnees)
{
    struct etat_bataille bataille;
    struct ennemi* p;
    struct etat_partie* partie;

    printf("===== tester_ennemis =====\n");
    printf("Initialisation...\n");
    partie = creer_partie();
    charger_partie(partie, "Nom Test", VRAI);
    init_etat_bataille(&bataille, partie, donnees);
    printf("Termine\n");
    printf("Ajout de quatre ennemis...\n");
    ajouter_ennemi(&bataille.ennemis, 0, 1, 2, donnees);
    ajouter_ennemi(&bataille.ennemis, 0, 3, 4, donnees);
    ajouter_ennemi(&bataille.ennemis, 1, 5, 6, donnees);
    ajouter_ennemi(&bataille.ennemis, 1, 7, 8, donnees);
    printf("Termine\n");
    printf("Contenu de la liste :\n");
    p = bataille.ennemis.prem;
    while(p)
    {
        printf("id : %u, x : %u, y : %u\n", p->id, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir : (1, 7, 8) ; (1, 5, 6) ; (0, 3, 4) ; (0, 1, 2)\n");
    printf("Suppression du (0, 3, 4)\n");
    supprimer_ennemi(&bataille.ennemis, bataille.ennemis.prem->suiv->suiv);
    printf("Contenu de la liste :\n");
    p = bataille.ennemis.prem;
    while(p)
    {
        printf("id : %u, x : %u, y : %u\n", p->id, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir : (1, 7, 8) ; (1, 5, 6) ; (0, 1, 2)\n");
    printf("Suppression du (1, 7, 8)\n");
    supprimer_ennemi(&bataille.ennemis, bataille.ennemis.prem);
    printf("Contenu de la liste :\n");
    p = bataille.ennemis.prem;
    while(p)
    {
        printf("id : %u, x : %u, y : %u\n", p->id, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir : (1, 5, 6) ; (0, 1, 2)\n");
    printf("Suppression du (0, 1, 2)\n");
    supprimer_ennemi(&bataille.ennemis, bataille.ennemis.prem->suiv);
    printf("Contenu de la liste :\n");
    p = bataille.ennemis.prem;
    while(p)
    {
        printf("id : %u, x : %u, y : %u\n", p->id, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir : (1, 5, 6)\n");
    printf("Liberation de la memoire...\n");
    detruire_etat_bataille(&bataille);
    detruire_partie(partie);
    printf("Termine\n");
    printf("===== fin tester_ennemis =====\n");
}



void tester_projectiles(const struct base_donnees* donnees)
{
    struct etat_bataille bataille;
    struct projectile* p;
    struct etat_partie* partie;

    printf("===== tester_projectiles =====\n");
    partie = creer_partie();
    charger_partie(partie, "Nom Test", VRAI);
    printf("Initialisation...\n");
    init_etat_bataille(&bataille, partie, donnees);
    printf("Termine\n");
    printf("Ajout de quatre projectiles...\n");
    ajouter_projectile(&bataille.projectiles, 0, 1, HAUT, 2, 3, VRAI);
    ajouter_projectile(&bataille.projectiles, 0, 4, DROITE, 5, 6, VRAI);
    ajouter_projectile(&bataille.projectiles, 1, 7, BAS, 8, 9, FAUX);
    ajouter_projectile(&bataille.projectiles, 1, 10, GAUCHE, 11, 12, FAUX);
    printf("Termine\n");
    printf("Contenu de la liste :\n");
    p = bataille.projectiles.prem;
    while(p)
    {
        printf("id : %u, Puiss : %u, Orientation : %d, Coord(%u, %u)\n",
               p->id, p->puissance, p->orientation, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir\n: (1, 10, 3, 11, 12)\n"
           "(1, 7, 2, 8, 9)\n(0, 4, 1, 5, 6)\n(0, 1, 0, 2, 3)\n");
    printf("Suppression du (0, 4, 1, 5, 6)\n");
    supprimer_projectile(&bataille.projectiles, bataille.projectiles.prem->suiv->suiv);
    printf("Contenu de la liste :\n");
    p = bataille.projectiles.prem;
    while(p)
    {
        printf("id : %u, Puiss : %u, Orientation : %d, Coord(%u, %u)\n",
               p->id, p->puissance, p->orientation, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir :\n(1, 10, 3, 11, 12)\n(1, 7, 2, 8, 9)\n(0, 1, 0, 2, 3)\n");
    printf("Suppression du (1, 10, 3, 11, 12)\n");
    supprimer_projectile(&bataille.projectiles, bataille.projectiles.prem);
    printf("Contenu de la liste :\n");
    p = bataille.projectiles.prem;
    while(p)
    {
        printf("id : %u, Puiss : %u, Orientation : %d, Coord(%u, %u)\n",
               p->id, p->puissance, p->orientation, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir :\n(1, 7, 2, 8, 9)\n(0, 1, 0, 2, 3)\n");
    printf("Suppression du (0, 1, 0, 2, 3)\n");
    supprimer_projectile(&bataille.projectiles, bataille.projectiles.prem->suiv);
    printf("Contenu de la liste :\n");
    p = bataille.projectiles.prem;
    while(p)
    {
        printf("id : %u, Puiss : %u, Orientation : %d, Coord(%u, %u)\n",
               p->id, p->puissance, p->orientation, p->coord_x, p->coord_y);
        p = p->suiv;
    }
    printf("On doit avoir\n: (1, 7, 2, 8, 9)\n");
    printf("Liberation de la memoire...\n");
    detruire_etat_bataille(&bataille);
    detruire_partie(partie);
    printf("Termine\n");
    printf("===== fin tester_projectiles =====\n");
}



void tester_saisie(void)
{
    struct resume_saisie saisie;

    /*
     * en guise de test, on va tourner dans une boucle et permettre a
     * l'utilisateur de voir si toutes les commandes reagissent convenablement
     */
    printf("===== tester_saisie =====\n");
    printf("Initialisation...\n");
    init_resume_saisie(&saisie);
    printf("Termine\n");

    do
    {
        recolter_evenements(&saisie);
        printf("Deplacement : ");
        switch(saisie.orientation)
        {
            case NEUTRE:
                printf("n");
                break;
            case HAUT:
                printf("h");
                break;
            case DROITE:
                printf("d");
                break;
            case BAS:
                printf("b");
                break;
            case GAUCHE:
                printf("g");
                break;
            default:
                break;
        }
        printf(" Tir : ");
        switch(saisie.direction_tir)
        {
            case NEUTRE:
                printf("n");
                break;
            case HAUT:
                printf("h");
                break;
            case DROITE:
                printf("d");
                break;
            case BAS:
                printf("b");
                break;
            case GAUCHE:
                printf("g");
                break;
            default:
                break;
        }
        printf("\n");
    } while(!saisie.quitte);

    printf("===== fin tester_saisie =====\n");
}
